package de.uni_saarland.coli.doclists.index;

import java.util.ArrayList;
import java.util.List;

import de.uni_saarland.coli.doclists.document.iterator.IDocumentIterator;
import de.uni_saarland.coli.doclists.index.docmentmanager.DiscDocumentManager;
import de.uni_saarland.coli.doclists.index.docmentmanager.IDocumentManager;
import de.uni_saarland.coli.doclists.index.docmentmanager.MemoryDocumentManager;
import de.uni_saarland.coli.doclists.suffixtree.IEdgeManager;
import de.uni_saarland.coli.doclists.suffixtree.INodeManager;
import de.uni_saarland.coli.doclists.suffixtree.STreeNode;
import de.uni_saarland.coli.doclists.suffixtree.TreeConstuctor;
import de.uni_saarland.coli.doclists.suffixtree.TreeSearch;
import de.uni_saarland.coli.doclists.suffixtree.disc.DiscNodeManager;
import de.uni_saarland.coli.doclists.suffixtree.memory.MemoryEdgeManager;
import de.uni_saarland.coli.doclists.suffixtree.memory.MemoryNodeManager;
import de.uni_saarland.coli.doclists.texttools.ITextTokenizer;
import de.uni_saarland.coli.doclists.texttools.SimpleTextTokenizer;

/**
 * 
 * @author stefan
 * 
 *         Basic index
 * 
 *         contains:
 * 
 *         Documents, Dictionary, Suffix tree edges and Suffix tree nodes
 */
public class Index implements IDiscIO {

	private static Index instance = null;

	public static Index instance() {
		return instance;
	}

	/**
	 * The dictionary
	 */
	private IDictionary termDictionary;
	/**
	 * The document manager
	 */
	private IDocumentManager documentManager;
	/**
	 * the tokenizer
	 */
	private ITextTokenizer textTokenizer;
	/**
	 * the edge map
	 */
	private IEdgeManager edgeMap;
	/**
	 * the node map
	 */
	private INodeManager nodeMap;

	private TreeConstuctor constructor;
	private TreeSearch search;
	
	/**
	 * Constructor.
	 * 
	 * @param termDictionary
	 *            the term dictionary
	 * @param documentManager
	 *            the document manager
	 * @param textTokenizer
	 *            the text tokenizer
	 * @param edgeMap
	 *            the edge map
	 * @param nodeMap
	 *            the node map
	 */
	private Index(IDictionary termDictionary, IDocumentManager documentManager,
			ITextTokenizer textTokenizer, IEdgeManager edgeMap, INodeManager nodeMap) {

		this.constructor = new TreeConstuctor();
		this.search = new TreeSearch();
		
		this.termDictionary = termDictionary;
		this.documentManager = documentManager;
		this.textTokenizer = textTokenizer;
		this.edgeMap = edgeMap;
		this.nodeMap = nodeMap;
	}

	/**
	 * Initializers the index.
	 * 
	 * @param termDictionary
	 *            the term dictionary
	 * @param documentManager
	 *            the document manager
	 * @param textTokenizer
	 *            the text tokenizer
	 * @param edgeMap
	 *            the edge map
	 * @param nodeMap
	 *            the node map
	 */
	public static void initialize(IDictionary termDictionary,
			IDocumentManager documentManager, ITextTokenizer textTokenizer,
			IEdgeManager edgeMap, INodeManager nodeMap) {
		instance = new Index(termDictionary, documentManager, textTokenizer,
				edgeMap, nodeMap);
	}

	/**
	 * Intitializes the Index with memory based data structures. e.g: Term
	 * dictionary = MemoryDictionary Text tokenizer = SimpleTextTokenizer
	 * Document Manager = MemoryDocumentManager Edge map = MemoryEdgeMap Node
	 * map = MemoryNodeMap
	 */
	public static void initializeMemoryIndex() {
		IDictionary dict = new MemoryDictionary();
		initialize(dict, new MemoryDocumentManager(), new SimpleTextTokenizer(
				dict), new MemoryEdgeManager(), new MemoryNodeManager());
	}

	/**
	 * Intitializes the Index with disc based data structures. e.g: Term
	 * dictionary = MemoryDictionary (Maybe TODO) Text tokenizer =
	 * SimpleTextTokenizer Document Manager = DiscDocumentManager Edge map =
	 * MemoryEdgeMap (TODO) Node map = DiscNodeMap
	 */
	public static void initializeDiscIndex() {
		IDictionary dict = new MemoryDictionary();
		initialize(dict, new DiscDocumentManager(1000),
				new SimpleTextTokenizer(dict), new MemoryEdgeManager(),
				new DiscNodeManager(100));
	}

	/**
	 * Adds the iterators documents to the index. Uses the default tokenizer.
	 * 
	 * @param docIter
	 *            a document iterator
	 */
	public void addDocuments(IDocumentIterator docIter) {
		if (this.textTokenizer != null) {
			this.documentManager.addDocuments(docIter, this.textTokenizer,false);
		} else {
			throw new RuntimeException("no tokenizer");
		}
	}

	/**
	 * Adds the iterators documents to the index
	 * 
	 * @param docIter
	 *            a document iterator
	 * @param tokenizer
	 *            a text tokenizer
	 */
	public void addDocuments(IDocumentIterator docIter, ITextTokenizer tokenizer) {
		this.documentManager.addDocuments(docIter, tokenizer,false);
	}

	public STreeNode search(String x) {
		this.textTokenizer.startText(x);
		List<Integer> query = new ArrayList<Integer>();
		while (this.textTokenizer.hasNext())
			query.add(getTextTokenizer().next());
		
		return this.search.find(query);
	}

	@Override
	public void save(String path, String baseName) {
		this.termDictionary.save(path, baseName);
		this.documentManager.save(path, baseName);
		this.edgeMap.save(path, baseName);
		this.nodeMap.save(path, baseName);
	}

	@Override
	public void open(String path, String baseName) {
		this.termDictionary.open(path, baseName);
		this.documentManager.open(path, baseName);
		this.edgeMap.open(path, baseName);
		this.nodeMap.open(path, baseName);
	}

	public static void indexDocuments(IDocumentIterator iter) {
		instance.getDocumentManager().addDocuments(iter, getTextTokenizer(), true);

		instance.addDocuments(iter);
	}
	
	/**
	 * Returns the term dictionary.
	 * 
	 * @return the term dictionary
	 */
	public static IDictionary getTermDictionary() {
		return instance.termDictionary;
	}

	/**
	 * Return the document manager.
	 * 
	 * @return the document manager
	 */
	public static IDocumentManager getDocumentManager() {
		return instance.documentManager;
	}

	/**
	 * Returns the text tokenizer.
	 * 
	 * @return the text tokenizer
	 */
	public static ITextTokenizer getTextTokenizer() {
		return instance.textTokenizer;
	}

	/**
	 * Returns the edge map.
	 * 
	 * @return the edge map
	 */
	public static IEdgeManager getEdgeMap() {
		return instance.edgeMap;
	}

	/**
	 * Returns the node map.
	 * 
	 * @return the node map
	 */
	public static INodeManager getNodeMap() {
		return instance.nodeMap;
	}
	
	public static TreeConstuctor getTreeConstructor() {
		return instance.constructor;
	}

	public static TreeSearch getTreeSearch() {
		return instance.search;
	}

	public static STreeNode find(String x) {
		return instance.search(x);
	}
}
